import logging
import sys
from PySide6.QtCore import QObject,Signal


class EmittingStream(QObject):
    """ Класс для перехвата консольного вывода """
    textSignal = Signal(str)
    def write(self,text):
        self.textSignal.emit(f"{text}")
    def flush(self):
        """ Заглушка """
        pass

class MyQtLogHandler(logging.StreamHandler):
    """кастомный хэндлер для логирования

    Args:
        logging (_type_): _description_
    """
    on_same_line = False

    def emit(self, record):
        try:
            msg = self.format(record)
            stream:EmittingStream = self.stream
            same_line = hasattr(record, 'same_line')
            if self.on_same_line and not same_line:
                stream.write(self.terminator)
            stream.write(msg)
            if same_line:
                stream.write('... ')
                self.on_same_line = True
            else:
                stream.write(self.terminator)
                self.on_same_line = False
            self.flush()
        except (KeyboardInterrupt, SystemExit):
            raise
        except:
            self.handleError(record)

class CustomFormatter(logging.Formatter):

    header = "\x1b[96m"
    deb = "\x1b[94m"    
    grey = "\x1b[38;20m"
    green = "\x1b[92m"
    yellow = "\x1b[33;20m"
    red = "\x1b[31;20m"
    bold_red = "\x1b[31;1m"
    reset = "\x1b[0m"

    dt="<i style='color:silver'>%(asctime)s.%(msecs)03d</i>"
    debug_lev="<span style='color:AliceBlue'>%(levelname)s</span>"
    info_lev ="<span style='color:olive'>%(levelname)s</span>" 
    warn_lev ="<span style='color:SandyBrown'>%(levelname)s</span>" 
    error_lev ="<span style='color:crimson'>%(levelname)s</span>"
    critical_lev ="<b style='color:red'>%(levelname)s</b>"

    format = "%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
    my_datefmt = "%d.%m.%Y %H:%M:%S"
    isConsole:bool = False

    format_type="simple" # simple, console, html 

    FORMATS_CONS = {
        logging.DEBUG: f"{header}%(asctime)s.%(msecs)03d{reset} - %(name)s - {deb}%(levelname)s{reset} - %(message)s",
        logging.INFO: f"{header}%(asctime)s.%(msecs)03d{reset} - %(name)s - {green}%(levelname)s{reset} - %(message)s",
        logging.WARNING: f"{header}%(asctime)s.%(msecs)03d{reset} - %(name)s - {yellow}%(levelname)s{reset} - %(message)s",
        logging.ERROR: f"{header}%(asctime)s.%(msecs)03d{reset} - %(name)s - {red}%(levelname)s{reset} - %(message)s",       
        logging.CRITICAL: f"{header}%(asctime)s.%(msecs)03d{reset} - %(name)s - {bold_red}%(levelname)s{reset} - %(message)s"
    }

    FORMATS_HTML = {
        logging.DEBUG: f"{dt} - %(name)s - {debug_lev} - %(message)s",
        logging.INFO: f"{dt} - %(name)s - {info_lev} - %(message)s",
        logging.WARNING: f"{dt} - %(name)s - {warn_lev} - %(message)s",
        logging.ERROR: f"{dt} - %(name)s - {error_lev} - %(message)s",       
        logging.CRITICAL: f"{dt} - %(name)s - {critical_lev} - %(message)s"
    }

    simple_file_format = "%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s"
    file_format="%(asctime)s.%(msecs)03d - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"

    def format(self, record):
        log_fmt = self.simple_file_format
        if self.format_type=="console": log_fmt=self.FORMATS_CONS.get(record.levelno)
        elif self.format_type=="html": log_fmt=self.FORMATS_HTML.get(record.levelno)
        # log_fmt = self.FORMATS_CONS.get(record.levelno) if self.isConsole else self.simple_file_format
        if record.levelno>=logging.WARNING and self.format_type=="simple": log_fmt=self.file_format
        formatter = logging.Formatter(log_fmt,datefmt=self.my_datefmt)
        return formatter.format(record)
    
    def set_console(self):
        self.isConsole=True

    def set_format_type(self,ftype:str="simple"):
        self.format_type=ftype

class MyLogger(logging.Logger):
    
    def __init__(self, name: str, outStream:EmittingStream, level = logging.DEBUG , log_file:str="default.py",mode="a") -> None:        
        super().__init__(name,level)
        self.__init_handlers(log_file,mode,outStream)

    
    def logger_init(self,lg:logging.Logger):
        self=lg

    def __init_handlers(self,log_file:str,mode:str,stream:EmittingStream):
        fh = logging.FileHandler(log_file,mode=mode,encoding="utf-8")
        ch = logging.StreamHandler()
        qh = MyQtLogHandler()
        qh.setStream(stream)
        ch.setLevel(logging.DEBUG)
        fh.setLevel(logging.DEBUG)
        qh.setLevel(logging.DEBUG)
        fileFormatter = CustomFormatter()
        consoleFormatter:CustomFormatter = CustomFormatter()
        consoleFormatter.set_format_type("console")
        qtFormatter:CustomFormatter = CustomFormatter()
        qtFormatter.set_format_type("html")
        fh.setFormatter(fileFormatter)
        ch.setFormatter(consoleFormatter)
        qh.setFormatter(qtFormatter)
        self.addHandler(fh)
        self.addHandler(ch)
        if not isinstance(stream,type(sys.stdout)): self.addHandler(qh)
        

